package com.izkml.mlyun.hotreload.websocket.handler;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.izkml.mlyun.hotreload.debug.connect.DebugConnector;
import com.izkml.mlyun.hotreload.debug.manager.BreakpointManager;
import com.izkml.mlyun.hotreload.debug.manager.WebSocketSessionManager;
import com.izkml.mlyun.hotreload.debug.protocol.Response;
import com.izkml.mlyun.hotreload.debug.protocol.ResultVo;
import com.izkml.mlyun.hotreload.debug.protocol.Variable;
import com.izkml.mlyun.hotreload.debug.util.DebugUtil;
import com.izkml.mlyun.hotreload.enums.ErrorEnums;
import com.izkml.mlyun.hotreload.enums.ResultTypeEnums;
import com.izkml.mlyun.hotreload.model.debug.AddBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.EnableBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.RemoveBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.RunToSpecifiedLineRequest;
import com.izkml.mlyun.hotreload.service.DebugFacadeService;
import com.izkml.mlyun.hotreload.websocket.WebSocketUtil;
import com.izkml.mlyun.hotreload.websocket.message.ReceiveMessage;
import com.microsoft.java.debug.core.DebugSettings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class DebugWebSocketHandler extends TextWebSocketHandler {

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        log.info("DebugWebSocket失去连接，关闭debug相关连接");
        // 1、取消所有断点
        List<String> list = BreakpointManager.removeAllBreakpoints(session.getId());
        if (ObjectUtil.isNotEmpty(list)) {
            list.forEach(x->DebugConnector.getInstance().removeClassBreakpoints(x));
        }
        // 2、可能存在的暂停线程，发送继续执行的命令
        String threadId = WebSocketSessionManager.getThreadId(session.getId());
        if (ObjectUtil.isNotEmpty(threadId)) {
            DebugConnector.getInstance().continueStep(Long.valueOf(threadId));
        }
        // 3、移除session
        WebSocketSessionManager.removeWebSocketSession(session);
        // 4、所有的session都不存在，则直接断开调试连接
//        if (WebSocketSessionManager.isEmpty()){
//            DebugConnector.getInstance().disconnect();
//        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("DebugWebSocket建立连接");
//        String query = session.getUri().getQuery();
//        Map<String, String> paramMap = HttpUtil.decodeParamMap(query, StandardCharsets.UTF_8);
//        String hostName = paramMap.get("hostName");
//        Assert.notNull(hostName,"hostName不能为空！");
//        String port = paramMap.get("port");
//        Assert.notNull(port,"port不能为空！");
        String hostName = "127.0.0.1";
        String port = "7544";
        //1、获取DebugConnector对象
        DebugConnector debugConnector = DebugConnector.getInstance();
        if (!debugConnector.connected) {
            //设置属性
            DebugSettings.getCurrent().showToString = false;
            DebugSettings.getCurrent().showQualifiedNames = true;
            //attach调试服务器
            String reqSeq = debugConnector.attach(hostName, Integer.parseInt(port));
            Response response = DebugUtil.getResponse(reqSeq);
            if (response == null || !response.success) {
                WebSocketUtil.sendError(session, ErrorEnums.SERVER_ERROR);
//                session.close();
                return;
            } else {
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.TIP,"连接调试服务器成功"));
            }
            //启动事件监听
            debugConnector.configurationDone();
            debugConnector.connected = true;
        }
        //2、新建立的Session添加到管理类中
        WebSocketSessionManager.addWebSocketSession(session);
        //3、返回 连接信息
        Map map = new HashMap<>();
        map.put("sessionId", session.getId());
        WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.CONNECT, map));
    }

//    @Override
    public void handleReceiveMessage(WebSocketSession session, ReceiveMessage receiveMessage){
        try {
            String method = receiveMessage.getMethod();
            /**
             * addBreakpoints   添加断点
             * removeBreakpoints    取消断点
             * enableBreakpoints    禁用/启用断点
             * runToSpecifiedLine   运行到指定代码行(下一代码段)
             * runToNextBreakpointLine  运行到下一断点
             * nextStep 下一步（单步）
             * getVariablesByStackFrameId   通过栈帧标识获取变量详细
             * getVariablesByReference  通过变量标识获取变量详细
             */
            String sessionId = session.getId();
            DebugFacadeService debugFacadeService = SpringUtil.getBean(DebugFacadeService.class);
            if ("addBreakpoints".equals(method)) {
                AddBreakpointsRequest request = JSONUtil.toBean(JSONUtil.toJsonStr(receiveMessage.getParams()), AddBreakpointsRequest.class);
                request.setSessionId(sessionId);
                debugFacadeService.addBreakpoints(request);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "添加断点成功!"));
            } else if ("removeBreakpoints".equals(method)) {
                RemoveBreakpointsRequest request = JSONUtil.toBean(JSONUtil.toJsonStr(receiveMessage.getParams()), RemoveBreakpointsRequest.class);
                request.setSessionId(sessionId);
                debugFacadeService.removeBreakpoints(request);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "取消断点成功!"));
            } else if ("overrideBreakpoints".equals(method)) {
                AddBreakpointsRequest request = JSONUtil.toBean(JSONUtil.toJsonStr(receiveMessage.getParams()), AddBreakpointsRequest.class);
                request.setSessionId(sessionId);
                debugFacadeService.overrideBreakpoints(request);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "覆盖断点成功!"));
            } else if ("enableBreakpoints".equals(method)) {
                EnableBreakpointsRequest request = JSONUtil.toBean(JSONUtil.toJsonStr(receiveMessage.getParams()), EnableBreakpointsRequest.class);
                request.setSessionId(sessionId);
                debugFacadeService.enableBreakpoints(request);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, request.getEnable() == Boolean.TRUE ? "启用断点成功!" : "禁用断点成功!"));
            } else if ("runToSpecifiedLine".equals(method)) {
                RunToSpecifiedLineRequest request = JSONUtil.toBean(JSONUtil.toJsonStr(receiveMessage.getParams()), RunToSpecifiedLineRequest.class);
                request.setSessionId(sessionId);
                debugFacadeService.runToSpecifiedLine(request);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "运行到指定代码行成功!"));
            } else if ("runToNextBreakpointLine".equals(method)) {
                debugFacadeService.runToNextBreakpointLine(sessionId);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "运行到下一断点成功!"));
            } else if ("nextStep".equals(method)) {
                debugFacadeService.nextStep(sessionId);
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "下一步成功!"));
            } else if ("getVariablesByStackFrameId".equals(method)) {
                Integer stackFrameId = Integer.parseInt(String.valueOf(receiveMessage.getParams()));
                List<Variable> variables = debugFacadeService.getVariablesByStackFrameId(stackFrameId, sessionId);
//                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.VARIABLE, variables));
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "通过栈帧标识获取变量详细成功!"));
            } else if ("getVariablesByReference".equals(method)) {
                Integer variablesReference = Integer.parseInt(String.valueOf(receiveMessage.getParams()));
                List<Variable> variables = debugFacadeService.getVariablesByReference(variablesReference, sessionId);
//                Map<String, Object> resultMap = new HashMap<>();
//                resultMap.put("paramVariable",variablesReference);
//                resultMap.put("variables",variables);
//                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.VARIABLE_ATTRIBUTE, resultMap));
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "通过变量标识获取变量详细成功!"));
            } else if ("commandnd".equals(method)) {
                DebugConnector debugConnector = DebugConnector.getInstance();
                debugConnector.sendTextMsg(JSONUtil.toJsonStr(receiveMessage.getParams()));
                WebSocketUtil.sendSuccess(session, ResultVo.build(ResultTypeEnums.RESPONSE, "收到消息!"));
            } else {
                WebSocketUtil.sendError(session, ErrorEnums.METHOD_NOT_FOUND);
            }
        } catch (Exception e){
            log.error("WebSocket异常",e);
            WebSocketUtil.sendError(session, ErrorEnums.SERVER_ERROR, e.getMessage());
        }
    }
}
